www.gusucode.com > VC++ 以多种方式处理位图文件的例子源码程序 > VC++ 以多种方式处理位图文件的例子源码程序\code\dibimage.cpp

    //Download by http://www.NewXing.com
/*
Module : DIBIMAGE.CPP
Purpose: Implementation for an MFC class that encapsulates DIBs
         and supports a variety of image manipulation functions on it
Created: PJN / DIBSECTION/1 / 23-07-1997
History: None

Copyright (c) 1997 by PJ Naughter.  
All rights reserved.

*/

/////////////////////////////////  Includes  //////////////////////////////////
#include "stdafx.h"
#include "math.h"
#include "dibimage.h"
#include "resource.h"






////////////////////////////// Future additions ///////////////////////////////
/*
BOOL CDibImage::TraceContourFilter()
BOOL CDibImage::EqualizeHistogram()
BOOL CDibImage::StretchHistogram()
BOOL CDibImage::MosaicFilter(int BlockSize)
BOOL CDibImage::DespeckleFilter()
BOOL CDibImage::DilateFilter()
BOOL CDibImage::EmbossFilter()
BOOL CDibImage::ErodeFilter()
BOOL CDibImage::SoftenFilter()
BOOL CDibImage::SharpenFilter()
BOOL CDibImage::UnSharpenFilter()
BOOL CDibImage::Posterize(int BitsPerChannel)
BOOL CDibImage::Solerize(int Threshold)
BOOL CDibImage::CirleDeform()
BOOL CDibImage::HorizontalCylinderDeform()
BOOL CDibImage::VerticalCylinderDeform()
BOOL CDibImage::MotionBlurDeform()
BOOL CDibImage::PentagonDeform()
BOOL CDibImage::PerspectiveHorizontalDeform()
BOOL CDibImage::PerspectiveVerticalDeform()
BOOL CDibImage::PinchDeform()
BOOL CDibImage::PunchDeform()
BOOL CDibImage::SkewDeform()
BOOL CDibImage::WindDeform()
BOOL CDibImage::ModifyHistogram(int* TransformTable, int nSize);
BOOL CDibImage::Resize(const CSize& size);
BOOL CDibImage::Resample(const CSize& size);
static BOOL CDibImage::ArithmeticAdd(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
static BOOL CDibImage::ArithmeticSubtract(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
static BOOL CDibImage::ArithmeticMultiply(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
static BOOL CDibImage::ArithmeticDifference(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
static BOOL CDibImage::ArithmeticDarkest(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
static BOOL CDibImage::ArithmeticLightest(CDibImage& dib1, CDibImage& dib2, int Divisor, int Bias, BOOL bClip);
BOOL CDibImage::SpacialFilter();
*/






///////////////////////////////// defines /////////////////////////////////////

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



//////////////////////////////// Implementation ///////////////////////////////

C3By3Filter::C3By3Filter()
{
  //Default filter is a filter which will not do anything to the image
  for (int i=0; i<3; i++)
    for (int j=0; j<3; j++)
      m_nValues[i][j] = 0;

  m_nValues[1][1] = 1;
  m_nDivision = 1;
  m_nBias = 0;
}


COLORREF C3By3Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
  int r = 0;
  int g = 0;
  int b = 0;
  for (int i=0; i<3; i++)
  {
    for (int j=0; j<3; j++)
    {
      COLORREF c;
      if (dibImage.GetPixel(x+i-1, y+j-1, c, lpDibBits))
      {
        r += (m_nValues[i][j] * GetRValue(c));
        g += (m_nValues[i][j] * GetGValue(c));
        b += (m_nValues[i][j] * GetBValue(c));
      }
    }
  }

  ASSERT(m_nDivision);
  r = min(r/m_nDivision + m_nBias, 255);
  g = min(g/m_nDivision + m_nBias, 255);
  b = min(b/m_nDivision + m_nBias, 255);
  r = max(r, 0);
  g = max(g, 0);
  b = max(b, 0);

  return RGB(r, g, b);
}



C3By3MedianFilter::C3By3MedianFilter()
{
}


COLORREF C3By3MedianFilter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
  int nPixels = 0;
  
  for (int k=0; k<9; k++)
    m_Ordered[k] = 0;

  for (int i=0; i<3; i++)
  {
    for (int j=0; j<3; j++)
    {
      COLORREF c;
      if (dibImage.GetPixel(x+i-1, y+j-1, c, lpDibBits))
      {
        m_Ordered[nPixels] = c;
        nPixels++;
      }
    }
  }

  qsort(&m_Ordered, nPixels, sizeof(COLORREF), CompareFunc);
  return m_Ordered[nPixels/2];
}


int C3By3MedianFilter::CompareFunc(const void *elem1, const void *elem2)
{
  COLORREF c1 = *(COLORREF*)elem1;
  COLORREF c2 = *(COLORREF*)elem2;

  if (c1 == c2)
    return 0;
  else 
  {
    BYTE r1 = GetRValue(c1);
    BYTE g1 = GetGValue(c1);
    BYTE b1 = GetBValue(c1);
    BYTE r2 = GetRValue(c2);
    BYTE g2 = GetGValue(c2);
    BYTE b2 = GetBValue(c2);

    if ((r1 + g1 + b1) > (r2 + g2 + b2))
      return 1;
    else
      return -1;
  }
}



C5By5Filter::C5By5Filter()
{
  //Default filter is a filter which will not do anything to the image
  for (int i=0; i<5; i++)
    for (int j=0; j<5; j++)
      m_nValues[i][j] = 0;

  m_nValues[2][2] = 1;
  m_nDivision = 1;
  m_nBias = 0;
}


COLORREF C5By5Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
  int r = 0;
  int g = 0;
  int b = 0;
  for (int i=0; i<5; i++)
  {
    for (int j=0; j<5; j++)
    {
      COLORREF c;
      if (dibImage.GetPixel(x+i-2, y+j-2, c, lpDibBits))
      {
        r += (m_nValues[i][j] * GetRValue(c));
        g += (m_nValues[i][j] * GetGValue(c));
        b += (m_nValues[i][j] * GetBValue(c));
      }
    }
  }

  ASSERT(m_nDivision);
  r = min(r/m_nDivision + m_nBias, 255);
  g = min(g/m_nDivision + m_nBias, 255);
  b = min(b/m_nDivision + m_nBias, 255);
  r = max(r, 0);
  g = max(g, 0);
  b = max(b, 0);

  return RGB(r, g, b);
}



C7By7Filter::C7By7Filter()
{
  //Default filter is a filter which will not do anything to the image
  for (int i=0; i<7; i++)
    for (int j=0; j<7; j++)
      m_nValues[i][j] = 0;

  m_nValues[3][3] = 1;
  m_nDivision = 1;
  m_nBias = 0;
}


COLORREF C7By7Filter::Filter(CDibImage& dibImage, LPSTR lpDibBits, int x, int y)
{
  int r = 0;
  int g = 0;
  int b = 0;
  for (int i=0; i<7; i++)
  {
    for (int j=0; j<7; j++)
    {
      COLORREF c;
      if (dibImage.GetPixel(x+i-3, y+j-3, c, lpDibBits))
      {
        r += (m_nValues[i][j] * GetRValue(c));
        g += (m_nValues[i][j] * GetGValue(c));
        b += (m_nValues[i][j] * GetBValue(c));
      }
    }
  }

  ASSERT(m_nDivision);
  r = min(r/m_nDivision + m_nBias, 255);
  g = min(g/m_nDivision + m_nBias, 255);
  b = min(b/m_nDivision + m_nBias, 255);
  r = max(r, 0);
  g = max(g, 0);
  b = max(b, 0);

  return RGB(r, g, b);
}



CUndoNode::CUndoNode(CDibImage* pImage, const CString& sDescription)
{
  m_pImage = pImage;
  m_sDescription = sDescription;
}


CUndoNode::~CUndoNode()
{
  delete m_pImage;
  m_pImage = NULL;
}



CDibImage::CDibImage()
{
  m_hDib = NULL;
  m_pWorkingArea = NULL;
  m_nWidth = 0;
  m_nHeight = 0;
  m_nScanWidth = 0;
  m_nBitsPerPixel = 0;
  m_Pal = NULL;

  m_nUndoSize = 4;  //By default, we support 4 levels of undo, if you
                    //want more (at the expense of memory usage) just
                    //call SetUndoSize will the level you want
}


CDibImage::CDibImage(const CDibImage& ds)
{
  m_hDib = NULL;
  m_pWorkingArea = NULL;
  m_nWidth = 0;
  m_nHeight = 0;
  m_nScanWidth = 0;
  m_nBitsPerPixel = 0;
  m_Pal = NULL;

  m_nUndoSize = 4;  //By default, we support 4 levels of undo, if you
                    //want more (at the expense of memory usage) just
                    //call SetUndoSize will the level you want

  Attach((HDIB) CopyHandle(ds.m_hDib));
  SetWorkingArea(ds.m_pWorkingArea->Clone());
}


CDibImage::~CDibImage()
{
  Destroy();

  //empty the redo stack
  for (int i=0; i<m_RedoStack.GetSize(); i++)
  {
    CUndoNode* pNode = m_RedoStack.GetAt(i);
    delete pNode;
    pNode = NULL;
  }  
  m_RedoStack.SetSize(0);

  //empty the undo stack
  for (i=0; i<m_UndoStack.GetSize(); i++)
  {
    CUndoNode* pNode = m_UndoStack.GetAt(i);
    delete pNode;
    pNode = NULL;
  }  
  m_UndoStack.SetSize(0);
}


CDibImage& CDibImage::operator=(const CDibImage& ds)
{
  Attach((HDIB) CopyHandle(ds.m_hDib));
  SetWorkingArea(ds.m_pWorkingArea->Clone());
  return *this;
}


BOOL CDibImage::Create(CSize size, WORD nBitCount)
{
  Destroy();

  BOOL bSuccess = TRUE;
	CWindowDC dcScreen(NULL);

	// should not already have palette
	ASSERT(m_Pal == NULL);

	// Select specified palette
  m_Pal = ::CreateHalftonePalette(dcScreen.m_hDC);
  if (m_Pal == NULL)
    return FALSE;

  // Fill in the BITMAPINFO Structure
  BITMAPINFO bmi;
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = size.cx;
	bmi.bmiHeader.biHeight = size.cy;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = nBitCount;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biSizeImage = 0;
	bmi.bmiHeader.biXPelsPerMeter = 0;
	bmi.bmiHeader.biYPelsPerMeter = 0;
  int nPaletteSize = ComputePaletteSize(nBitCount);
	bmi.bmiHeader.biClrUsed = nPaletteSize;
	bmi.bmiHeader.biClrImportant = nPaletteSize;

  m_nWidth = size.cx;
  m_nHeight = size.cy;
  m_nBitsPerPixel = nBitCount;
  m_nScanWidth = WIDTHBYTES(m_nWidth*m_nBitsPerPixel);
  m_pWorkingArea = new CRectWorkingArea(Rect());

  DWORD dwSize = sizeof(bmi) + m_nScanWidth*m_nHeight;
  m_hDib = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize);
	if (m_hDib == NULL)
		return FALSE;
	LPSTR pDib = (LPSTR) ::GlobalLock((HGLOBAL) m_hDib);
  memcpy(pDib, &bmi, sizeof(bmi));
  ::GlobalUnlock((HGLOBAL) m_hDib);


  return bSuccess;
}


int CDibImage::ComputePaletteSize(DWORD nBitCount)
{
  int nSize = 0;
	switch(nBitCount) 
  {
		case 1:  nSize = 2;     break;
		case 4:  nSize = 16;    break;
		case 8:	 nSize = 256;   break;
		case 16:
		case 24:
		case 32: nSize = 0;		  break;
		default: ASSERT(FALSE); break;
	}

  return nSize;
}


void CDibImage::Destroy()
{
  if (m_pWorkingArea)
  {
    delete m_pWorkingArea;
    m_pWorkingArea = NULL;
  }

  if (m_hDib)
    GlobalFree(m_hDib);

  DeleteObject(m_Pal);
}


BOOL CDibImage::Attach(HGLOBAL hGlobal)
{
  Destroy();

  BOOL bSuccess = FALSE;
  if (hGlobal)
  {
    m_hDib = (HDIB) hGlobal;
    DWORD dwSize = GlobalSize(m_hDib);
    ASSERT(dwSize);
  	LPSTR lpDib = (LPSTR) ::GlobalLock(m_hDib);
    ASSERT(lpDib);
    m_nWidth = ::DIBWidth(lpDib);
    m_nHeight = ::DIBHeight(lpDib);
	  ::GlobalUnlock((HGLOBAL) m_hDib);
    m_nBitsPerPixel = GetBitsPerPixel();
    m_nScanWidth = WIDTHBYTES(m_nWidth*m_nBitsPerPixel);
    m_pWorkingArea = new CRectWorkingArea(Rect());
    CPalette pal;
	  ::CreateDIBPalette(m_hDib, &pal);
    m_Pal = (HPALETTE) pal.Detach();
    bSuccess = TRUE;
  }

  return bSuccess;
}


BOOL CDibImage::Load(LPCTSTR lpszPathName)
{
  CFile f;
  if (!f.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite))
	  return FALSE;

  return Attach(::ReadDIBFile(f));
}


BOOL CDibImage::Load(HINSTANCE hInst, LPCTSTR lpResourceName)
{
  HRSRC hSrc = FindResource(hInst, lpResourceName, RT_BITMAP);
  BOOL bSuccess = FALSE;
  if (hSrc)
  {
    HGLOBAL hResData = LoadResource(hInst, hSrc);
    if (hResData)
    {
      LPVOID lpResData = LockResource(hResData);
      if (lpResData)
      {
        DWORD dwSize = SizeofResource(hInst, hSrc);
        if (dwSize)
        {
          HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwSize);
          if (hGlobal)
          {
            LPVOID lpBitmapData = GlobalLock(hGlobal);
            if (lpBitmapData)
            {
              CopyMemory(lpBitmapData, lpResData, dwSize);
              GlobalUnlock(hGlobal);
              bSuccess = Attach(hGlobal);
            }
          }
        }
      }
    }
  }
  
  return bSuccess;
}


int CDibImage::GetBitsPerPixel() const
{
  int nBitCount;
  if (m_hDib == NULL)
    nBitCount = 0;
  else
  {
  	LPSTR lpDib = (LPSTR) ::GlobalLock(m_hDib);

	  //  Calculate the number of bits per pixel for the DIB.
	  if (IS_WIN30_DIB(lpDib))
		  nBitCount = ((LPBITMAPINFOHEADER)lpDib)->biBitCount;
	  else
		  nBitCount = ((LPBITMAPCOREHEADER)lpDib)->bcBitCount;

	 	::GlobalUnlock((HGLOBAL) m_hDib);
  }

	return nBitCount;
}


BOOL CDibImage::Draw(CDC& dc, const CRect* rcDst, const CRect* rcSrc, CPalette* pPal)
{
  CRect DCRect(Rect());
  if (rcDst)
    DCRect = *rcDst;

  CRect DibRect(Rect());
  if (rcSrc)
    DibRect = *rcSrc;

  CPalette pal;
  pal.Attach(m_Pal);
  CPalette* pPalette = NULL;
  if (pPal)
    pPalette = pPal;
  else
    pPalette = &pal;

  BOOL bSuccess = ::PaintDIB(dc.m_hDC, &DCRect, m_hDib,	&DibRect,	pPalette);
  pal.Detach();
  return bSuccess;
}


BOOL CDibImage::GetPixel(int x, int y, COLORREF& value, LPSTR lpDibBits) const
{
  if (m_hDib == NULL)
    return FALSE;

  //Currently only support pixel access for 24 bit images
  //May support other formats in the future
  if (m_nBitsPerPixel != 24)
    return FALSE;

  //position is out of range
  if (x >= m_nWidth || x < 0 || y >= m_nHeight || y < 0)
    return FALSE;

  BOOL bLocked = FALSE;
  if (lpDibBits == NULL)
  {
	  LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	  lpDibBits = ::FindDIBBits(lpDibHdr);
    bLocked = TRUE;
  }

  BYTE* pData = (BYTE*) lpDibBits + (m_nHeight-1-y)*m_nScanWidth + x*3;
  value = RGB(pData[2], pData[1], pData[0]);

  if (bLocked)
    ::GlobalUnlock((HGLOBAL) m_hDib);

  return TRUE;
}


BOOL CDibImage::SetPixel(int x, int y, const COLORREF& value, LPSTR lpDibBits)
{
  if (m_hDib == NULL)
    return FALSE;

  //Currently only support pixel access for 24 bit images
  //May support other formats in the future
  if (m_nBitsPerPixel != 24)
    return FALSE;

  //check the position
  ASSERT(x < m_nWidth && x >= 0 && y < m_nHeight && y >= 0);

  BOOL bLocked = FALSE;
  if (lpDibBits == NULL)
  {
	  LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	  lpDibBits = ::FindDIBBits(lpDibHdr);
    bLocked = TRUE;
  }

  BYTE* pData = (BYTE*) lpDibBits + (m_nHeight-1-y)*m_nScanWidth + x*3;  //THIS NEEDS TO BE TESTED

  pData[0] = GetBValue(value);
  pData[1] = GetGValue(value);
  pData[2] = GetRValue(value);

  if (bLocked)
    ::GlobalUnlock((HGLOBAL) m_hDib);

  return TRUE;
}


BOOL CDibImage::Save(LPCTSTR lpszPathName)
{
  CFile f;
  if (!f.Open(lpszPathName, CFile::shareDenyWrite | CFile::modeCreate | CFile::modeWrite))
	  return FALSE;
  else
    return SaveDIB(m_hDib, f);
}


BOOL CDibImage::CopySelection(CDibImage& dib)
{
  if (m_hDib == NULL)
    return FALSE;

  BOOL bSuccess = FALSE;
  ASSERT(m_pWorkingArea);
  CRect r = m_pWorkingArea->BoundingRectangle();
  bSuccess = dib.Create(CSize(r.Width(), r.Height()), 24);

  if (bSuccess)
  {
 	  LPSTR lpDibHdrSrc  = (LPSTR) ::GlobalLock(m_hDib);
	  LPSTR lpDibBitsSrc = ::FindDIBBits(lpDibHdrSrc);
 	  LPSTR lpDibHdrDest  = (LPSTR) ::GlobalLock(dib.m_hDib);
	  LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
    for (int y=r.top; bSuccess && y<r.bottom; y++)
    {
      for (int x=r.left; bSuccess && x<r.right; x++)
      {
        if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
        {
          COLORREF c;
          bSuccess = GetPixel(x, y, c, lpDibBitsSrc);
          bSuccess = bSuccess && dib.SetPixel(x-r.left, y-r.top, c, lpDibBitsDest);
        }
      }
    }
    GlobalUnlock((HGLOBAL) dib.m_hDib);
    GlobalUnlock((HGLOBAL) m_hDib);
  }

  return bSuccess;
}



LPSTR CDibImage::GetDIBBits()
{
 	LPSTR lpDibHdrSrc  = (LPSTR) ::GlobalLock(m_hDib);
	return ::FindDIBBits(lpDibHdrSrc);
}


BOOL CDibImage::CopyToClipboard()
{
  if (m_hDib == NULL)
    return FALSE;

  BOOL bSuccess = FALSE;
	if (OpenClipboard(NULL))
	{
		if (EmptyClipboard())
    {
      CDibImage DibCopy;
      bSuccess = CopySelection(DibCopy);
      if (bSuccess)
      {
        HDIB hNewDib = (HDIB) CopyHandle(DibCopy.m_hDib);
		    bSuccess = (::SetClipboardData(CF_DIB, hNewDib) != NULL);
      }
    }

		CloseClipboard();
	}
  return bSuccess;
}


BOOL CDibImage::PasteFromClipboard()
{
  BOOL bSuccess = FALSE;
	if (OpenClipboard(NULL))
	{
		HDIB hNewDib = (HDIB) CopyHandle(::GetClipboardData(CF_DIB));
		CloseClipboard();
		if (hNewDib != NULL)
      bSuccess = Attach(hNewDib);
	}

  return bSuccess;
}


BOOL CDibImage::PasteAvailable()
{
	return IsClipboardFormatAvailable(CF_DIB);
}


void CDibImage::SetUndoSize(int nUndoSize)
{
  m_nUndoSize = nUndoSize;

  if (m_nUndoSize < m_UndoStack.GetSize())
    TRACE("Losing some of the undo stack in CDibImage::SetUndoSize\n");

  for (int i=m_nUndoSize; i<m_UndoStack.GetSize(); i++)
  {
    CUndoNode* pNode = m_UndoStack.GetAt(i);
    delete pNode;
  }

  for (i=m_nUndoSize; i<m_RedoStack.GetSize(); i++)
  {
    CUndoNode* pNode = m_RedoStack.GetAt(i);
    delete pNode;
  }

  //Trim back the size of the arrays if necessary
  if (m_UndoStack.GetSize() > nUndoSize)
    m_UndoStack.SetSize(m_nUndoSize);

  if (m_RedoStack.GetSize() > nUndoSize)
    m_RedoStack.SetSize(m_nUndoSize);
}


BOOL CDibImage::SaveState(UINT nID)
{
  CString sDescription;
  sDescription.LoadString(nID);
  return SaveState(sDescription);
}


BOOL CDibImage::SaveState(const CString& sDescription)
{
  //if there is no undo stack then return immediately
  if (m_nUndoSize == 0)
    return FALSE;

  //If we have reached the limit of the undo stack
  //then drop the oldest undo by moving all the items
  //down in the stack
  if (m_UndoStack.GetSize() == m_nUndoSize)
  {
    TRACE("Undo stack size exceeded, discarding oldest\n");
    CUndoNode* pNode = m_UndoStack.GetAt(0);
    delete pNode;

    for (int i=1; i<m_UndoStack.GetSize(); i++)
    {
      CUndoNode* pNode = m_UndoStack.GetAt(i);
      m_UndoStack.SetAt(i-1, pNode);
    }  
    m_UndoStack.SetSize(m_nUndoSize-1);
  }

  CDibImage* pCopy = new CDibImage(*this);
  CUndoNode* pNode = new CUndoNode(pCopy, sDescription);
  m_UndoStack.Add(pNode);
  return TRUE;
}


BOOL CDibImage::UndoAvailable()
{
  return (m_UndoStack.GetSize() > 0);
}


BOOL CDibImage::Undo()
{
  BOOL bSuccess = FALSE;
  int nIndex = m_UndoStack.GetUpperBound();
  if (nIndex >= 0)
  {
    //Add the current image to the redo stack
    CDibImage* pCopy = new CDibImage(*this);
    CUndoNode* pNode1 = new CUndoNode(pCopy, m_sCurrentDescription);
    m_RedoStack.Add(pNode1);

    //Remove from the undo stack and 
    //reinstate the current value
    CUndoNode* pNode2 = m_UndoStack.GetAt(nIndex);
    operator=(*pNode2->GetImage());
    pNode1->SetDescription(pNode2->GetDescription());
    delete pNode2;
    m_UndoStack.RemoveAt(nIndex);

    bSuccess = TRUE;
  }
  return bSuccess;
}


BOOL CDibImage::Redo()
{
  BOOL bSuccess = FALSE;
  int nIndex = m_RedoStack.GetUpperBound();
  if (nIndex >= 0)
  {
    //Add the current image to the undo stack
    CDibImage* pCopy = new CDibImage(*this);
    CUndoNode* pNode1 = new CUndoNode(pCopy, m_sCurrentDescription);
    m_UndoStack.Add(pNode1);

    //Remove from the redo stack and 
    //reinstate the current value
    CUndoNode* pNode2 = m_RedoStack.GetAt(nIndex);
    operator=(*pNode2->GetImage());
    pNode1->SetDescription(pNode2->GetDescription());
    delete pNode2;
    m_RedoStack.RemoveAt(nIndex);

    bSuccess = TRUE;
  }
  return bSuccess;
}


BOOL CDibImage::RedoAvailable()
{
  return (m_RedoStack.GetSize() > 0);
}


CString CDibImage::UndoDescription() const
{
  CString rVal;
  int nIndex = m_UndoStack.GetUpperBound();
  if (nIndex >= 0)
  {
    CUndoNode* pNode = m_UndoStack.GetAt(nIndex);
    rVal = pNode->GetDescription();
  }
  return rVal;
}


CString CDibImage::RedoDescription() const
{
  CString rVal;
  int nIndex = m_RedoStack.GetUpperBound();
  if (nIndex >= 0)
  {
    CUndoNode* pNode = m_RedoStack.GetAt(nIndex);
    rVal = pNode->GetDescription();
  }
  return rVal;
}


CWorkingArea* CDibImage::GetWorkingArea()
{
  return m_pWorkingArea;
}


void CDibImage::SetWorkingArea(CWorkingArea* pWorkingArea)
{
  if (m_pWorkingArea)
  {
    delete m_pWorkingArea;
    m_pWorkingArea = NULL;
  }
  m_pWorkingArea = pWorkingArea;
}


BOOL CDibImage::SetColor(COLORREF color)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_SETCOLOR);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
        bSuccess = SetPixel(x, y, color, lpDibBits);
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::Flip()
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_FLIP);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);


  int nMiddle = r.Height()/2 + r.top;
  
  for (int y=nMiddle; bSuccess && y>r.top; y--)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c1;
        int y1 = nMiddle + (nMiddle - y);
        bSuccess = GetPixel(x, y1, c1, lpDibBits);
        
        COLORREF c2;
        bSuccess = bSuccess && GetPixel(x, y, c2, lpDibBits);

        bSuccess = bSuccess && SetPixel(x, y, c1, lpDibBits);
        bSuccess = bSuccess && SetPixel(x, y1, c2, lpDibBits);
      }
    }
  }

  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::Mirror()
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_MIRROR);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);


  int nMiddle = r.Width()/2 + r.left;
  
  for (int x=nMiddle; bSuccess && x>r.left; x--)
  {
    for (int y=r.top; bSuccess && y<r.bottom; y++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c1;
        int x1 = nMiddle + (nMiddle - x);
        bSuccess = GetPixel(x1, y, c1, lpDibBits);
        
        COLORREF c2;
        bSuccess = bSuccess && GetPixel(x, y, c2, lpDibBits);

        bSuccess = bSuccess && SetPixel(x, y, c1, lpDibBits);
        bSuccess = bSuccess && SetPixel(x1, y, c2, lpDibBits);
      }
    }
  }

  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustBrightness(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_BRIGHTNESS);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int r = min(GetRValue(c)*Percentage/100, 255);
          int g = min(GetGValue(c)*Percentage/100, 255);
          int b = min(GetBValue(c)*Percentage/100, 255);
          r = max(r, 0);
          g = max(g, 0);
          b = max(b, 0);
          c = RGB(r, g, b);
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustContrast(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_CONTRAST);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        bSuccess = GetPixel(x, y, c, lpDibBits);
        int r = min(128 + ((GetRValue(c) - 128)*Percentage/100), 255);
        int g = min(128 + ((GetGValue(c) - 128)*Percentage/100), 255);
        int b = min(128 + ((GetBValue(c) - 128)*Percentage/100), 255);
        r = max(r, 0);
        g = max(g, 0);
        b = max(b, 0);
        c = RGB(r, g, b);
        bSuccess = SetPixel(x, y, c, lpDibBits);
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustGammaCorrection(float Value)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_GAMMA);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
  double MaxRange = pow((double) 255, (double) Value) / 255;


 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        bSuccess = GetPixel(x, y, c, lpDibBits);

        double dblR = pow((double) GetRValue(c), (double) Value) / MaxRange;
        double dblG = pow((double) GetGValue(c), (double) Value) / MaxRange;
        double dblB = pow((double) GetBValue(c), (double) Value) / MaxRange;

        int r = min((int) (dblR+0.5), 255);
        int g = min((int) (dblG+0.5), 255);
        int b = min((int) (dblB+0.5), 255);
        r = max(r, 0);
        g = max(g, 0);
        b = max(b, 0);
        c = RGB(r, g, b);
        bSuccess = SetPixel(x, y, c, lpDibBits);
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustHighLight(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_HIGHLIGHT);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        bSuccess = GetPixel(x, y, c, lpDibBits);
        int r = GetRValue(c);
        int g = GetGValue(c);
        int b = GetBValue(c);
        int l = r+g+b;
        if ((l > (170*3)))
        {
          r = min(r*Percentage/100, 255);
          g = min(g*Percentage/100, 255);
          b = min(b*Percentage/100, 255);
          r = max(r, 0);
          g = max(g, 0);
          b = max(b, 0);
          c = RGB(r, g, b);
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustMidtone(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_MIDTONE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        bSuccess = GetPixel(x, y, c, lpDibBits);
        int r = GetRValue(c);
        int g = GetGValue(c);
        int b = GetBValue(c);
        int l = r+g+b;
        if ((l >= (85*3)) && (l <= (170*3)))
        {
          r = min(r*Percentage/100, 255);
          g = min(g*Percentage/100, 255);
          b = min(b*Percentage/100, 255);
          r = max(r, 0);
          g = max(g, 0);
          b = max(b, 0);
          c = RGB(r, g, b);
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustShadow(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_SHADOW);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        bSuccess = GetPixel(x, y, c, lpDibBits);
        int r = GetRValue(c);
        int g = GetGValue(c);
        int b = GetBValue(c);
        int l = r+g+b;
        if (l < (85*3))
        {
          r = min(r*Percentage/100, 255);
          g = min(g*Percentage/100, 255);
          b = min(b*Percentage/100, 255);
          r = max(r, 0);
          g = max(g, 0);
          b = max(b, 0);
          c = RGB(r, g, b);
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustHue(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_HUE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          double H;
          double S;
          double L;
          RGBtoHSL(c, &H, &S, &L);
          H = (H*Percentage/100);
          bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustSaturation(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_SATURATION);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          double H;
          double S;
          double L;
          RGBtoHSL(c, &H, &S, &L);
          S = (S*Percentage/100);
          bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustHSL(int PercentHue, int PercentSaturation, int PercentLuminosity)
{
  if (m_hDib == NULL)
    return FALSE;

  if (PercentHue < 0)
    return FALSE;

  if (PercentSaturation < 0)
    return FALSE;

  if (PercentLuminosity < 0)
    return FALSE;


  SaveState(IDS_DI_UNDO_ADJUST_HSL);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          double H;
          double S;
          double L;
          RGBtoHSL(c, &H, &S, &L);
          S = (S*PercentSaturation/100);
          H = (H*PercentHue/100);
          L = (L*PercentLuminosity/100);
          bSuccess = SetPixel(x, y, HLStoRGB(H, L, S), lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


WORD CDibImage::GetVersion()
{
  return 0x0101;  //ie 1.01     

  /* Revision History

  1.0  18/11/1997:  Initial Public Release
  1.01 10/11/1998:  See help file for changes

  */
}


void CDibImage::RGBtoHSL(COLORREF rgb, double* H, double* S, double* L)
{
  double delta;
  double r = (double)GetRValue(rgb)/255;
  double g = (double)GetGValue(rgb)/255;
  double b = (double)GetBValue(rgb)/255;
  double cmax = max(r,max(g,b));
  double cmin = min(r,min(g,b));
  *L = (cmax+cmin)/2.0;
  if (cmax == cmin) 
  {
    *S = 0;
    *H = 0; // it's really undefined
  } 
  else 
  {
    if (*L < 0.5) 
      *S = (cmax-cmin)/(cmax+cmin);
    else
      *S = (cmax-cmin)/(2.0-cmax-cmin);
    delta = cmax - cmin;
    if (r==cmax)
      *H = (g-b)/delta;
    else if (g==cmax)
      *H = 2.0 +(b-r)/delta;
    else
      *H = 4.0+(r-g)/delta;
    *H /= 6.0;
    if (*H < 0.0)
      *H += 1;
  }
}


double CDibImage::HuetoRGB(double m1, double m2, double h)
{
  if (h < 0) 
    h += 1.0;
  if (h > 1) 
    h -= 1.0;
  if (6.0*h < 1)
    return (m1+(m2-m1)*h*6.0);
  if (2.0*h < 1)
    return m2;
  if (3.0*h < 2.0)
    return (m1+(m2-m1)*((2.0/3.0)-h)*6.0);
  return m1;
}


COLORREF CDibImage::HLStoRGB(const double& H, const double& L, const double& S)
{
  double r,g,b;
  double m1, m2;

  if (S==0) 
  {
    r=g=b=L;
  } 
  else 
  {
    if (L <= 0.5)
      m2 = L*(1.0+S);
    else
      m2 = L+S-L*S;
    m1 = 2.0*L-m2;
    r = HuetoRGB(m1, m2, H+1.0/3.0);
    g = HuetoRGB(m1, m2, H);
    b = HuetoRGB(m1, m2, H-1.0/3.0);
  }
  return RGB((BYTE)(r*255),(BYTE)(g*255),(BYTE)(b*255));
}


BOOL CDibImage::AdjustRed(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_RED);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int r = min(GetRValue(c)*Percentage/100, 255);
          r = max(r, 0);
          c = RGB(r, GetGValue(c), GetBValue(c));
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustGreen(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_GREEN);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int g = min(GetGValue(c)*Percentage/100, 255);
          g = max(g, 0);
          c = RGB(GetRValue(c), g, GetBValue(c));
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::AdjustBlue(int Percentage)
{
  if (m_hDib == NULL)
    return FALSE;

  if (Percentage < 0)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_BLUE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
  for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int b = min(GetBValue(c)*Percentage/100, 255);
          b = max(b, 0);
          c = RGB(GetRValue(c), GetGValue(c), b);
          bSuccess = SetPixel(x, y, c, lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::Greyscale()
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_GREYSCALE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int val = ((GetRValue(c) + GetGValue(c) + GetBValue(c)) / 3);
          bSuccess = SetPixel(x, y, RGB(val, val, val), lpDibBits);
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::Negate()
{
  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADJUST_NEGATE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
          bSuccess = SetPixel(x, y, RGB(255 - GetRValue(c), 255 - GetGValue(c), 255 - GetBValue(c)), lpDibBits);
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::FindEdgesFilter()
{
  if (m_hDib == NULL)
    return FALSE;

  C3By3Filter Filter1;
  Filter1.m_nValues[0][0] = -1;
  Filter1.m_nValues[0][1] = 0;
  Filter1.m_nValues[0][2] = 1;
  Filter1.m_nValues[1][0] = -2;
  Filter1.m_nValues[1][1] = 0;
  Filter1.m_nValues[1][2] = 2;
  Filter1.m_nValues[2][0] = -1;
  Filter1.m_nValues[2][1] = 0;
  Filter1.m_nValues[2][2] = 1;


  C3By3Filter Filter2;
  Filter2.m_nValues[0][0] = -1;
  Filter2.m_nValues[0][1] = -2;
  Filter2.m_nValues[0][2] = -1;
  Filter2.m_nValues[1][0] = 0;
  Filter2.m_nValues[1][1] = 0;
  Filter2.m_nValues[1][2] = 0;
  Filter2.m_nValues[2][0] = 1;
  Filter2.m_nValues[2][1] = 2;
  Filter2.m_nValues[2][2] = 1;


  CDibImage dibCopy;
  CopySelection(dibCopy);

  SaveState(IDS_DI_UNDO_FILTER);

  ASSERT(dibCopy.m_pWorkingArea);
  CRect rectSrc(dibCopy.m_pWorkingArea->BoundingRectangle());
  CRect rectDest(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdrSrc   = (LPSTR) ::GlobalLock(dibCopy.m_hDib);
	LPSTR lpDibBitsSrc  = ::FindDIBBits(lpDibHdrSrc);
 	LPSTR lpDibHdrDest  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
	for (int y=0; bSuccess && y<rectSrc.Height(); y++)
  {
    for (int x=0; bSuccess && x<rectSrc.Width(); x++)
    {
      if (dibCopy.m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c1 = Filter1.Filter(dibCopy, lpDibBitsSrc, x, y);
        COLORREF c2 = Filter2.Filter(dibCopy, lpDibBitsSrc, x, y);
        int r = max(GetRValue(c1), GetRValue(c2));
        int g = max(GetGValue(c1), GetGValue(c2));
        int b = max(GetBValue(c1), GetBValue(c2));
        bSuccess = SetPixel(x+rectDest.left, y+rectDest.top, RGB(r, g, b), lpDibBitsDest);
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


BOOL CDibImage::FindVerticalEdgesFilter()
{
  C3By3Filter Filter;
  Filter.m_nValues[0][0] = -1;
  Filter.m_nValues[0][1] = -2;
  Filter.m_nValues[0][2] = -1;
  Filter.m_nValues[1][0] = 0;
  Filter.m_nValues[1][1] = 0;
  Filter.m_nValues[1][2] = 0;
  Filter.m_nValues[2][0] = 1;
  Filter.m_nValues[2][1] = 2;
  Filter.m_nValues[2][2] = 1;

  return UserDefinedFilter(Filter);
}

BOOL CDibImage::FindHorizontalEdgesFilter()
{
  C3By3Filter Filter;
  Filter.m_nValues[0][0] = -1;
  Filter.m_nValues[0][1] = 0;
  Filter.m_nValues[0][2] = 1;
  Filter.m_nValues[1][0] = -2;
  Filter.m_nValues[1][1] = 0;
  Filter.m_nValues[1][2] = 2;
  Filter.m_nValues[2][0] = -1;
  Filter.m_nValues[2][1] = 0;
  Filter.m_nValues[2][2] = 1;

  return UserDefinedFilter(Filter);
}



BOOL CDibImage::BlurFilter()
{
  C7By7Filter Filter;

  for (int i=0; i<7; i++)
    for (int j=0; j<7; j++)
      Filter.m_nValues[i][j] = 0;
  Filter.m_nValues[3][3] = -4;
  Filter.m_nValues[2][2] = 1;
  Filter.m_nValues[2][3] = 4;
  Filter.m_nValues[2][4] = 1;
  Filter.m_nValues[3][2] = 4;
  Filter.m_nValues[3][4] = 4;
  Filter.m_nValues[4][2] = 1;
  Filter.m_nValues[4][3] = 4;
  Filter.m_nValues[4][4] = 1;
  Filter.m_nDivision = 16;

  return UserDefinedFilter(Filter);
}


BOOL CDibImage::AddNoiseFilter(int Percentage)
{
  if (Percentage <= 0 || Percentage > 100)
    return FALSE;

  if (m_hDib == NULL)
    return FALSE;

  SaveState(IDS_DI_UNDO_ADD_NOISE);

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      int test = rand();  
      BOOL bPass = test < (RAND_MAX*Percentage/100);
      if (bPass && m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        int r = rand()*256/RAND_MAX - 128;
        int g = rand()*256/RAND_MAX - 128;
        int b = rand()*256/RAND_MAX - 128;

        if (GetPixel(x, y, c, lpDibBits))
          bSuccess = SetPixel(x, y, RGB(GetRValue(c) + r, GetGValue(c) + g, GetBValue(c) + b), lpDibBits);
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;

}


BOOL CDibImage::MedianFilter()
{
  C3By3MedianFilter Filter;
  return UserDefinedFilter(Filter);
}


BOOL CDibImage::UserDefinedFilter(CUserDefinedFilter& Filter)
{
  if (m_hDib == NULL)
    return FALSE;

  CDibImage dibCopy;
  CopySelection(dibCopy);

  SaveState(IDS_DI_UNDO_FILTER);

  ASSERT(dibCopy.m_pWorkingArea);
  CRect rectSrc(dibCopy.m_pWorkingArea->BoundingRectangle());
  CRect rectDest(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdrSrc   = (LPSTR) ::GlobalLock(dibCopy.m_hDib);
	LPSTR lpDibBitsSrc  = ::FindDIBBits(lpDibHdrSrc);
 	LPSTR lpDibHdrDest  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBitsDest = ::FindDIBBits(lpDibHdrDest);
	for (int y=0; bSuccess && y<rectSrc.Height(); y++)
  {
    for (int x=0; bSuccess && x<rectSrc.Width(); x++)
    {
      if (dibCopy.m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c = Filter.Filter(dibCopy, lpDibBitsSrc, x, y);
        bSuccess = SetPixel(x+rectDest.left, y+rectDest.top, c, lpDibBitsDest);
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  if (!bSuccess)
    Undo();

  return bSuccess;
}


int CDibImage::ColorsUsed() const
{
  return 0;  //for the moment
}


BOOL CDibImage::SplitChannels(CDibImage& RedChannel, CDibImage& GreenChannel, CDibImage& BlueChannel)
{
  if (m_hDib == NULL)
    return FALSE;

  if (!RedChannel.Create(Size(), 24))
    return FALSE;

  if (!GreenChannel.Create(Size(), 24))
    return FALSE;

  if (!BlueChannel.Create(Size(), 24))
    return FALSE;

  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
 	LPSTR lpDibHdrRed  = (LPSTR) ::GlobalLock(RedChannel.m_hDib);
	LPSTR lpDibBitsRed = ::FindDIBBits(lpDibHdrRed);
 	LPSTR lpDibHdrGreen  = (LPSTR) ::GlobalLock(GreenChannel.m_hDib);
	LPSTR lpDibBitsGreen = ::FindDIBBits(lpDibHdrGreen);
 	LPSTR lpDibHdrBlue  = (LPSTR) ::GlobalLock(BlueChannel.m_hDib);
	LPSTR lpDibBitsBlue = ::FindDIBBits(lpDibHdrBlue);

  CRect r(Rect());
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      COLORREF c;
      if (GetPixel(x, y, c, lpDibBits))
      {
        int r = GetRValue(c);
        int g = GetGValue(c);
        int b = GetBValue(c);
        bSuccess = bSuccess && RedChannel.SetPixel(x, y, RGB(r, r, r), lpDibBitsRed);
        bSuccess = bSuccess && GreenChannel.SetPixel(x, y, RGB(g, g, g), lpDibBitsGreen);
        bSuccess = bSuccess && BlueChannel.SetPixel(x, y, RGB(b, b, b), lpDibBitsBlue);
      }
      else
        bSuccess = FALSE;
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);
  GlobalUnlock((HGLOBAL) RedChannel.m_hDib);
  GlobalUnlock((HGLOBAL) GreenChannel.m_hDib);
  GlobalUnlock((HGLOBAL) BlueChannel.m_hDib);

  return bSuccess;
}



BOOL CDibImage::GetRedChannel(CDibImage& red)
{
  if (m_hDib == NULL)
    return FALSE;

  if (!red.Create(Size(), 24))
    return FALSE;

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
 	LPSTR lpDibHdrRed  = (LPSTR) ::GlobalLock(red.m_hDib);
	LPSTR lpDibBitsRed = ::FindDIBBits(lpDibHdrRed);

  CRect r(Rect());
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      COLORREF c;
      if (GetPixel(x, y, c, lpDibBits))
      {
        int r = GetRValue(c);
        bSuccess = red.SetPixel(x, y, RGB(r, r, r), lpDibBitsRed);
      }
      else
        bSuccess = FALSE;
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);
  GlobalUnlock((HGLOBAL) red.m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetGreenChannel(CDibImage& green)
{
  if (m_hDib == NULL)
    return FALSE;

  if (!green.Create(Size(), 24))
    return FALSE;

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
 	LPSTR lpDibHdrGreen  = (LPSTR) ::GlobalLock(green.m_hDib);
	LPSTR lpDibBitsGreen = ::FindDIBBits(lpDibHdrGreen);

  CRect r(Rect());
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      COLORREF c;
      if (GetPixel(x, y, c, lpDibBits))
      {
        int g = GetGValue(c);
        bSuccess = green.SetPixel(x, y, RGB(g, g, g), lpDibBitsGreen);
      }
      else
        bSuccess = FALSE;
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);
  GlobalUnlock((HGLOBAL) green.m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetBlueChannel(CDibImage& blue)
{
  if (m_hDib == NULL)
    return FALSE;

  if (!blue.Create(Size(), 24))
    return FALSE;

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
 	LPSTR lpDibHdrBlue  = (LPSTR) ::GlobalLock(blue.m_hDib);
	LPSTR lpDibBitsBlue = ::FindDIBBits(lpDibHdrBlue);

  CRect r(Rect());
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      COLORREF c;
      if (GetPixel(x, y, c, lpDibBits))
      {
        int b = GetBValue(c);
        bSuccess = blue.SetPixel(x, y, RGB(b, b, b), lpDibBitsBlue);
      }
      else
        bSuccess = FALSE;
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);
  GlobalUnlock((HGLOBAL) blue.m_hDib);

  return bSuccess;
}


BOOL CDibImage::CombineChannels(const CDibImage& red, const CDibImage& green, const CDibImage& blue)
{
  if (red.m_hDib == NULL || green.m_hDib == NULL || blue.m_hDib == NULL)
    return FALSE;

  //All the images should be the same size
  if (red.Rect() != green.Rect() || green.Rect() != blue.Rect() || red.Rect() != blue.Rect())
    return FALSE;

  if (!Create(red.Size(), 24))
    return FALSE;


  BOOL bSuccess = TRUE;

 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
 	LPSTR lpDibHdrRed  = (LPSTR) ::GlobalLock(red.m_hDib);
	LPSTR lpDibBitsRed = ::FindDIBBits(lpDibHdrRed);
 	LPSTR lpDibHdrGreen  = (LPSTR) ::GlobalLock(green.m_hDib);
	LPSTR lpDibBitsGreen = ::FindDIBBits(lpDibHdrGreen);
 	LPSTR lpDibHdrBlue  = (LPSTR) ::GlobalLock(blue.m_hDib);
	LPSTR lpDibBitsBlue = ::FindDIBBits(lpDibHdrBlue);

  CRect r(Rect());
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      COLORREF r;
      COLORREF g;
      COLORREF b;
      if (red.GetPixel(x, y, r, lpDibBitsRed) &&
          green.GetPixel(x, y, g, lpDibBitsGreen) &&
          blue.GetPixel(x, y, b, lpDibBitsBlue))
      {
        COLORREF c = RGB(GetRValue(r), GetGValue(g), GetBValue(b));
        bSuccess = bSuccess && SetPixel(x, y, c, lpDibBits);
      }
      else
        bSuccess = FALSE;
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);
  GlobalUnlock((HGLOBAL) red.m_hDib);
  GlobalUnlock((HGLOBAL) green.m_hDib);
  GlobalUnlock((HGLOBAL) blue.m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetRedHistogram(int* RedChannel, int nSize)
{
  if (m_hDib == NULL)
    return FALSE;

  for (int i=0; i<nSize; i++)
    RedChannel[i] = 0;

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int r = GetRValue(c);
          if (r < nSize)
            RedChannel[r]++;
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetGreenHistogram(int* GreenChannel, int nSize)
{
  if (m_hDib == NULL)
    return FALSE;

  for (int i=0; i<nSize; i++)
    GreenChannel[i] = 0;

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int g = GetGValue(c);
          if (g < nSize)
            GreenChannel[g]++;
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetBlueHistogram(int* BlueChannel, int nSize)
{
  if (m_hDib == NULL)
    return FALSE;

  for (int i=0; i<nSize; i++)
    BlueChannel[i] = 0;

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int b = GetBValue(c);
          if (b < nSize)
            BlueChannel[b]++;
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  return bSuccess;
}


BOOL CDibImage::GetHistogram(int* RedChannel, int nRedSize, int* GreenChannel, int nGreenSize, int* BlueChannel, int nBlueSize)
{
  if (m_hDib == NULL)
    return FALSE;

  for (int i=0; i<nRedSize; i++)
    RedChannel[i] = 0;
  for (i=0; i<nGreenSize; i++)
    GreenChannel[i] = 0;
  for (i=0; i<nBlueSize; i++)
    BlueChannel[i] = 0;

  ASSERT(m_pWorkingArea);
  CRect r(m_pWorkingArea->BoundingRectangle());

  BOOL bSuccess = TRUE;
 	LPSTR lpDibHdr  = (LPSTR) ::GlobalLock(m_hDib);
	LPSTR lpDibBits = ::FindDIBBits(lpDibHdr);
	for (int y=r.top; bSuccess && y<r.bottom; y++)
  {
    for (int x=r.left; bSuccess && x<r.right; x++)
    {
      if (m_pWorkingArea->PointInSelection(CPoint(x, y)))
      {
        COLORREF c;
        if (GetPixel(x, y, c, lpDibBits))
        {
          int r = GetRValue(c);
          int g = GetGValue(c);
          int b = GetBValue(c);
          if (r < nRedSize)
            RedChannel[r]++;
          if (g < nGreenSize)
            GreenChannel[g]++;
          if (b < nBlueSize)
            BlueChannel[b]++;
        }
        else
          bSuccess = FALSE;
      }
    }
  }
  GlobalUnlock((HGLOBAL) m_hDib);

  return bSuccess;
}